<script setup lang="ts">
import { ColumnHeightOutlined, QuestionCircleOutlined, ReloadOutlined } from '@vicons/antd';

import { densityOptions } from '@/components/table/src/const';
import ColumnSetting from '@/components/table/src/components/column-setting.vue';
import { useAppearanceSettingStore } from '@/store/modules/appearance-setting';
import { useDataSource } from '@/components/table/src/hooks/use-data-source';
import type { BasicTableProps } from '@/components/table/src/props';
import { useLoading } from '@/components/table/src/hooks/use-loading';
import { usePagination } from '@/components/table/src/hooks/use-pagination';
import { useTableHeight } from '@/components/table/src/hooks/use-table-height';
import { useWindowSizeFn } from '@/hooks/event/use-window-size-fn';
import { useColumns } from '@/components/table/src/hooks/use-column';
import { createTableContext } from '@/components/table/src/context/use-table-context';
import type { TableActionType } from '@/components/table';
import { useTableWidth } from '@/components/table/src/hooks/use-table-width';

defineOptions({
  name: 'BasicTable',
});

const props = withDefaults(defineProps<BasicTableProps>(), {
  pagination: true,
  maxVisibleActionButtons: 2,
  valueField: 'id',
});

const emits = defineEmits<{
  (e: 'check', value: Array<string | number>): void;
  (e: 'fetch-success', res: any): void;
  (e: 'fetch-error', error: any): void;
}>();

const appTheme = computed(() => useAppearanceSettingStore().appTheme);

const tableElRef = ref<ComponentRef>(null);
const innerPropsRef = ref<Partial<BasicTableProps>>();

const getProps = computed(() => {
  return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
});

/**
 * loading
 */
const { getLoading, setLoading } = useLoading(getProps);

/**
 * 分页
 */
const { getPaginationInfo, setPagination } = usePagination(getProps);
const pagination = computed(() => toRaw(unref(getPaginationInfo)));
function handlePageChange(page: number) {
  setPagination({ page });
  reload();
}
function handlePageSizeChange(pageSize: number) {
  setPagination({ pageSize });
  reload();
}

/**
 * 表格数据源
 */
const { getDataSourceRef, reload } = useDataSource(
  getProps,
  getPaginationInfo,
  setPagination,
  setLoading,
  emits,
);

/**
 * 表格列
 */
const {
  setColumns,
  getColumns,
  getPageColumns,
  getCacheColumns,
  setCacheColumnsField,
  setSelection,
} = useColumns(getProps);

/**
 * 计算表格高度
 */
const { computeTableHeight, deviceHeight } = useTableHeight(tableElRef, pagination, null);
useWindowSizeFn(computeTableHeight as any, 280);
onMounted(() => {
  nextTick(() => {
    computeTableHeight();
  });
  setSelection(true);
});

/**
 * 计算表格宽度
 */
const contentWidth = useTableWidth(getPageColumns);

/**
 * 表格密度
 */
const getTableSize = computed(() => tableSize.value);
const tableSize = ref(unref(props as any).size || 'medium');
function densitySelect(e: string) {
  tableSize.value = e;
}

/**
 * 设置斑马纹
 */
const isStriped = ref(false);
function setStriped(val: boolean) {
  isStriped.value = val;
}

/**
 * 组装表格信息
 */
const getBindValues = computed(() => {
  const tableData = unref(getDataSourceRef);
  const columns = toRaw(unref(getPageColumns));
  const maxHeight = tableData.length ? `${unref(deviceHeight)}px` : 'auto';
  return {
    ...unref(getProps),
    'loading': unref(getLoading),
    columns,
    'data': tableData,
    'size': unref(getTableSize),
    'remote': true,
    'max-height': maxHeight,
    'row-key': (row: Recordable) => row[props.valueField],
    'scroll-x': contentWidth.value,
    'default-checked-row-keys': props.defaultCheckedRowKeys,
    'pagination': getPaginationInfo.value,
  };
});

/**
 * 选择
 */
function handleCheckRowKeys(
  keys: Array<string | number>,
  _rows: object[],
  _meta: { row: object | undefined; action: 'check' | 'uncheck' | 'checkAll' | 'uncheckAll' },
) {
  emits('check', keys);
}

const tableAction: TableActionType = {
  reload,
  setColumns,
  getColumns,
  getCacheColumns,
  emits,
  setCacheColumnsField,
  setSelection,
};

createTableContext({ ...tableAction, getBindValues });

defineExpose(tableAction);
</script>

<template>
  <div>
    <div class="table-toolbar">
      <div class="flex items-center table-toolbar-left">
        <template v-if="props.title">
          <div class="table-toolbar-left-title">
            {{ props.title }}
            <NTooltip v-if="props.titleTooltip" trigger="hover">
              <template #trigger>
                <NIcon size="18" class="ml-1 text-gray-400 cursor-pointer">
                  <QuestionCircleOutlined />
                </NIcon>
              </template>
              {{ props.titleTooltip }}
            </NTooltip>
          </div>
        </template>

        <slot name="tableTitle" />
      </div>

      <div class="flex items-center leading-none table-toolbar-right">
        <!-- 顶部右侧区域 -->
        <slot name="toolbar" />

        <!-- 斑马纹 -->
        <NTooltip trigger="hover">
          <template #trigger>
            <div class="mr-2 table-toolbar-right-icon">
              <NSwitch v-model:value="isStriped" @update:value="setStriped" />
            </div>
          </template>
          <span>表格斑马纹</span>
        </NTooltip>
        <NDivider vertical />

        <!-- 刷新 -->
        <NTooltip trigger="hover">
          <template #trigger>
            <div class="table-toolbar-right-icon" @click="reload">
              <NIcon size="18">
                <ReloadOutlined />
              </NIcon>
            </div>
          </template>
          <span>刷新</span>
        </NTooltip>

        <!-- 密度 -->
        <NTooltip trigger="hover">
          <template #trigger>
            <div class="table-toolbar-right-icon">
              <NDropdown
                v-model:value="tableSize"
                trigger="click"
                :options="densityOptions"
                @select="densitySelect"
              >
                <NIcon size="18">
                  <ColumnHeightOutlined />
                </NIcon>
              </NDropdown>
            </div>
          </template>
          <span>密度</span>
        </NTooltip>

        <ColumnSetting />
      </div>
    </div>
    <div class="s-table">
      <NDataTable
        ref="tableElRef"
        v-bind="getBindValues"
        :striped="isStriped"
        default-expand-all
        @update:page="handlePageChange"
        @update:page-size="handlePageSizeChange"
        @update:checked-row-keys="handleCheckRowKeys"
      >
        <template v-for="item of Object.keys($slots)" #[item]="data" :key="item">
          <slot :name="item" v-bind="data" />
        </template>
      </NDataTable>
    </div>
  </div>
</template>

<style lang="less" scoped>
.table-toolbar {
  display: flex;
  justify-content: space-between;
  padding: 0 0 16px 0;

  &-left {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex: 1;

    &-title {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      font-size: 16px;
      font-weight: 600;
    }
  }

  &-right {
    display: flex;
    justify-content: flex-end;
    flex: 1;

    &-icon {
      margin-left: 12px;
      font-size: 16px;
      cursor: pointer;
      color: var(--text-color);

      :hover {
        color: v-bind(appTheme);
      }
    }
  }
}

.table-toolbar-inner-popover-title {
  padding: 2px 0;
}
</style>
